package com.ejlchina.tool.util

import com.ejlchina.tool.bean.BleDeviceBean
import com.ejlchina.tool.constant.FIRMWARE_VERSION_PREFIX
import com.ejlchina.tool.constant.FIRMWARE_VERSION_PREFIX_OFFLINE
import com.ejlchina.tool.constant.HARDWARE_VERSION_PREFIX
import com.ejlchina.tool.constant.HARDWARE_VERSION_PREFIX_OFFLINE
import com.ejlchina.tool.singleton.SharedPreferenceUtil
import com.ejlchina.tool.util.bytearray.hex2ByteArray
import com.ejlchina.tool.util.bytearray.intTo32HexStringLE
import com.ejlchina.tool.util.bytearray.readByteArrayBE
import com.ejlchina.tool.util.bytearray.readInt32BE
import com.ejlchina.tool.util.bytearray.readInt32LE
import com.ejlchina.tool.util.bytearray.reversalEvery2Charts
import com.ejlchina.tool.util.bytearray.toHexString
import com.huyuhui.fastble.data.BleDevice
import kotlin.math.pow

fun getDownwardCommand(bleDevice: BleDeviceBean,commandHead: String,commandVariable: String): ByteArray{
    val commandString = commandHead + commandVariable + timestamp() + SharedPreferenceUtil.getString(bleDevice.bleDevice.mac)
    return commandString.hex2ByteArray()
}

/**
 * 获取下行指令的具体数据
 * 这个方法只适用于前4个直接微固定值
 */
fun getUpwardData(bytes: ByteArray,offset: Int = 1): ByteArray{
    val count = bytes[2].toInt()
    return bytes.readByteArrayBE(3 + offset,count - offset)
}

fun getIntFromByteArray(byteArray: ByteArray): Int{
    return byteArray.toHexString(false).toInt(16)
}

fun getVersionNo(byte: Byte,isFirmwareVersion: Boolean = true): String{
    val byteInt = byte.toInt()
    val andValue = 0xF
    val low = (byteInt and andValue).toString()
    val right = byteInt shr 4
    val high = (right and andValue).toString()
    val prefix = if (isFirmwareVersion) FIRMWARE_VERSION_PREFIX else HARDWARE_VERSION_PREFIX
    val suffix = if (isFirmwareVersion) "" else ".0"
    return "$prefix$high.$low$suffix"
}

fun getVersionNumber(byte: Byte,isFirmwareVersion: Boolean = true): Float{
    val byteInt = byte.toInt()
    val andValue = 0xF
    val low = (byteInt and andValue).toString()
    val right = byteInt shr 4
    val high = (right and andValue).toString()
    val suffix = if (isFirmwareVersion) "" else ".0"
    return "$high.$low$suffix".toFloat()
}

fun getVersionNoOffline(byte: Byte,isFirmwareVersion: Boolean = true): String{
    val byteInt = byte.toInt()
    val andValue = 0xF
    val low = (byteInt and andValue).toString()
    val right = byteInt shr 4
    val high = (right and andValue).toString()
    val prefix = if (isFirmwareVersion) FIRMWARE_VERSION_PREFIX_OFFLINE else HARDWARE_VERSION_PREFIX_OFFLINE
    val suffix = if (isFirmwareVersion) "" else ".0"
    return "$prefix$high.$low$suffix"
}

//index 从0开始
fun getBitValueFrom32Bits(byteArray: ByteArray, index: Int): Int{
    val byteArrayIntValue = byteArray.readInt32BE()
    val leftMove = 32 - 1 - index
    val rightMove = 32 - 1
    return (byteArrayIntValue shl leftMove) ushr  rightMove
}

//index 从0开始
fun getBitValueFrom8Bits(byte: Byte, index: Int): Int{
    val intValue = byte.toInt()
    val leftMove = 32 - 1 -index
    val rightMove = 32 - 1
    return (intValue shl leftMove) ushr rightMove
}

/**
 * 将二进制的某个位设置为1
 * 注意：index 从0开始
 */
fun setBitValue(originalValue: Int, index: Int): Int{
    val orValue = 2.0.pow(index)
    return originalValue + orValue.toInt()
}

fun timestamp(): String {
    val timestampNow = (System.currentTimeMillis() / 1000).toInt() + 8 * 3600
    return intTo32HexStringLE(timestampNow)
}

/**
 * 计算CRC16校验码
 *
 * @param bytes 需要计算的字节数组
 */
fun getCRC(bytes: ByteArray): Int {
    var crc = 0x0000ffff
    val polynomial = 0x0000a001
    var j: Int
    var i = 0
    while (i < bytes.size) {
        crc = crc xor (bytes[i].toInt() and 0x000000ff)
        j = 0
        while (j < 8) {
            if ((crc and 0x00000001) != 0) {
                crc = crc shr 1
                crc = crc xor polynomial
            } else {
                crc = crc shr 1
            }
            j++
        }
        i++
    }
    return crc
}


fun CRC16_MODBUS(buffer: ByteArray): Int {
    var wCRCin = 0xffff
    val POLYNOMIAL = 0xa001
    for (b in buffer) {
        wCRCin = wCRCin xor (b.toInt() and 0x00ff)
        for (j in 0..7) {
            if ((wCRCin and 0x0001) != 0) {
                wCRCin = wCRCin shr 1
                wCRCin = wCRCin xor POLYNOMIAL
            } else {
                wCRCin = wCRCin shr 1
            }
        }
    }
    return 0x0000.let { wCRCin = wCRCin xor it; wCRCin }
}